/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.mes.service.impl;

import com.xy.biz.base.client.BizCodeClient;
import com.xy.biz.base.client.GoodsBatchClient;
import com.xy.biz.base.client.GoodsClient;
import com.xy.biz.base.domain.req.GetBizCodeRequest;
import com.xy.biz.base.domain.resp.GetGoodsBatchResponse;
import com.xy.biz.base.domain.resp.GetGoodsResponse;
import com.xy.biz.mes.domain.bo.ManufactureOrderBO;
import com.xy.biz.mes.domain.converter.ManufactureOrderConverter;
import com.xy.biz.mes.domain.enums.ManufactureOrderStatusEnum;
import com.xy.biz.mes.domain.query.ManufactureOrderQuery;
import com.xy.biz.mes.domain.req.SaveManufactureOrderRequest;
import com.xy.biz.mes.manager.ManufactureOrderManager;
import com.xy.biz.mes.service.ManufactureOrderService;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.tuples.Triple;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.gid.service.GidService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zsp
 * @date 2022-1-6
 */
@Service
public class ManufactureOrderServiceImpl implements ManufactureOrderService {

    @Autowired
    private GidService gidService;
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private BizCodeClient bizCodeClient;
    @Autowired
    private GoodsBatchClient goodsBatchClient;
    @Autowired
    private ManufactureOrderManager manufactureOrderManager;

    @Override
    public Result<?> saveManufactureOrder(SaveManufactureOrderRequest request) {
        return saveAllManufactureOrder(Arrays.asList(request));
    }

    @Override
    public Result<?> saveAllManufactureOrder(Collection<SaveManufactureOrderRequest> collection) {
        Set<Long> goodsIdSet = new HashSet<>();
        Set<Long> goodsBatchIdSet = new HashSet<>();
        collection.forEach(order -> {
            order.getGoodsList().forEach(goods -> {
                goodsIdSet.add(goods.getGoodsId());
                if (!Objects.isNull(goods.getGoodsBatchId())) {
                    goodsBatchIdSet.add(goods.getGoodsBatchId());
                }
            });
        });
        List<GetGoodsResponse> goodsList = ResultUtils.get(goodsClient.listGoodsById(goodsIdSet));
        if (CollectionUtils.isEmpty(goodsList) || !Objects.equals(goodsIdSet.size(), goodsList.size())) {
            return Result.ofBadRequest("输入了不存在的货品");
        }
        Map<Long, GetGoodsResponse> goodsMap = goodsList.stream().collect(
                Collectors.toMap(GetGoodsResponse::getGoodsId, e -> e));
        Map<Long, GetGoodsBatchResponse> goodsBatchMap;
        if (!CollectionUtils.isEmpty(goodsBatchIdSet)) {
            List<GetGoodsBatchResponse> goodsBatchList = ResultUtils.get(goodsBatchClient.listGoodsBatchById(goodsBatchIdSet));
            if (CollectionUtils.isEmpty(goodsBatchList) || !Objects.equals(goodsBatchIdSet.size(), goodsBatchList.size())) {
                return Result.ofBadRequest("输入了不存在的货品批次");
            }
            goodsBatchMap = goodsBatchList.stream().collect(
                    Collectors.toMap(GetGoodsBatchResponse::getGoodsBatchId, e -> e));
        } else {
            goodsBatchMap = new HashMap<>();
        }
        LocalDateTime now = LocalDateTime.now();
        GetBizCodeRequest getBizCodeRequest = GetBizCodeRequest.builder().code("MO").build();
        List<ManufactureOrderBO> manufactureOrderList = ManufactureOrderConverter.toBO(collection);
        manufactureOrderList.forEach(order -> {
            order.setManufactureOrderId(gidService.generate());
            order.setManufactureOrderCode(ResultUtils.get(bizCodeClient.nextBizCode(getBizCodeRequest)));
            order.setStatus(ManufactureOrderStatusEnum.REGISTERED.getCode());
            order.getGoodsList().forEach(currentGoods -> {
                currentGoods.setManufactureOrderGoodsId(gidService.generate());
                currentGoods.setManufactureOrderId(order.getManufactureOrderId());
                currentGoods.setManufactureOrderCode(order.getManufactureOrderCode());
                GetGoodsResponse goods = goodsMap.get(currentGoods.getGoodsId());
                currentGoods.setGoodsCode(goods.getGoodsCode());
                currentGoods.setGoodsFullCode(goods.getGoodsFullCode());
                currentGoods.setGoodsAbbr(goods.getGoodsAbbr());
                //currentGoods.setUnit(goods.getUnit());
                GetGoodsBatchResponse goodsBatch = goodsBatchMap.get(currentGoods.getGoodsBatchId());
                if (!Objects.isNull(goodsBatch)) {
                    currentGoods.setGoodsBatchCode(goodsBatch.getGoodsBatchCode());
                    currentGoods.setConcentration(goodsBatch.getConcentration());
                    currentGoods.setConcentrationUnit(goodsBatch.getConcentrationUnit());
                    currentGoods.setProductionDate(goodsBatch.getProductionDate());
                    currentGoods.setExpirationDate(goodsBatch.getExpirationDate());
                }
                currentGoods.setTenantId(UserContextHolder.getTenantId());
            });
            order.setTenantId(UserContextHolder.getTenantId());
            order.setCreateUserId(UserContextHolder.getUserId());
            order.setCreateUserName(UserContextHolder.getUserName());
            order.setCreateUserGroupId(UserContextHolder.getUserGroupId());
            order.setCreateUserGroupName(UserContextHolder.getUserGroupName());
            order.setCreateTime(now);
            order.setUpdateTime(now);
        });
        int affectedRows = manufactureOrderManager.saveAllManufactureOrder(manufactureOrderList);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateManufactureOrder(ManufactureOrderBO manufactureOrderBO) {
        int affectedRows = manufactureOrderManager.updateManufactureOrder(manufactureOrderBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteManufactureOrder(Long manufactureOrderId) {
        int affectedRows = manufactureOrderManager.deleteManufactureOrder(manufactureOrderId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public ManufactureOrderBO getManufactureOrder(Long manufactureOrderId) {
        return manufactureOrderManager.getManufactureOrder(manufactureOrderId);
    }

    @Override
    public Triple<Long, Long, Long> getBomAndTechniqueAndTemplate(Long productionGoodsId) {
//        RecordTemplateBO recordTemplate = null; //TODO recordTemplateManager.getRecordTemplateByGoodsId(productionGoodsId);
//        return new Triple<>(0L,
//                0L,
//                recordTemplate == null ? 0L : recordTemplate.getRecordTemplateId());
        return null;
    }

    @Override
    public List<ManufactureOrderBO> listManufactureOrderById(Collection<Long> collection, boolean withGoods) {
        List<ManufactureOrderBO> manufactureOrderBOList = manufactureOrderManager.listManufactureOrderById(collection, withGoods);
        if (!CollectionUtils.isEmpty(manufactureOrderBOList) && withGoods) {
            manufactureOrderBOList.stream()
                    .filter(e -> !CollectionUtils.isEmpty(e.getGoodsList()))
                    .flatMap(e -> e.getGoodsList().stream())
                    .map(e -> e.calculateAttritionRate(e))
                    .collect(Collectors.toList());
        }
        return manufactureOrderBOList;
    }

    @Override
    public List<ManufactureOrderBO> listManufactureOrder(ManufactureOrderQuery query) {
        return manufactureOrderManager.listManufactureOrder(query);
    }

    @Override
    public int countManufactureOrder(ManufactureOrderQuery query) {
        return manufactureOrderManager.countManufactureOrder(query);
    }

}
